package metier;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.AccessException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.Scanner;

public class AgenceImpl implements AgenceItf {
	private int id;
	private static int IDENT_AUTO = 0;
	private List<Vehicule> listeVehicules;
	private String nom;
	private static List<AgenceItf> AutresAgences;

	public static void main(String[] args) throws RemoteException {
		String agence1 = "";
		String agence2 = "";
		String agence3 = "";
		AutresAgences = new ArrayList<AgenceItf>();

		Properties prop = new Properties();
		prop.clear();
		try {
			FileInputStream in = new FileInputStream("agence.properties");
			prop.load(in);
			agence1 = (String) prop.getProperty("agence1");
			agence2 = (String) prop.getProperty("agence2");
			agence3 = (String) prop.getProperty("agence3");
					
		} catch (IOException e) {
			e.printStackTrace();
		}

		// Si changement de la valeur d'un attribut de l'impl�mentation, le stub
		// est affect� ?

		// TODO Auto-generated method stub
		AgenceImpl monAgence = new AgenceImpl(agence1);
		// cr�er le stub (0 => port attribu� dynamiquement)
		AgenceItf stub = (AgenceItf) UnicastRemoteObject.exportObject(
				monAgence, 0);
		// lancer rmiregistry sur 1099 (port par d�faut)
		Registry myRegistry = LocateRegistry.createRegistry(Integer.parseInt(prop.getProperty("port")));
		// on binde le stub et pas l'objet
		myRegistry.rebind(agence1, stub);

		stub.ChargerAgences(AutresAgences, myRegistry, prop);

		for (AgenceItf a : AutresAgences) {
			a.ChargerAgences(AutresAgences, myRegistry, prop);
		}

		Scanner sc = new Scanner(System.in);

		while (true) {
			System.out.println("Quelle operation souhaitez-vous realiser?");
			System.out.println("1 : annuler une reservation");
			System.out.println("2 : reserver un vehicule");
			int action = sc.nextInt();
			sc = new Scanner(System.in);

			switch (action) {
			case 1:
				System.out.println("Saisissez l'id de la reservation");
				int id = sc.nextInt();
				sc = new Scanner(System.in);
				if (stub.annulerReservation(id)) {
					System.out
							.println("L'annulation de la reservation s'est déroulee avec succes.");
				} else
					System.out.println("Réservation introuvable");
				break;
			case 2:
				System.out.println("Saisissez la ville de depart");
				String villeDepart = sc.nextLine();
				sc = new Scanner(System.in);
				System.out.println("Saisissez la ville d'arrivee");
				String villeArrivee = sc.nextLine();
				sc = new Scanner(System.in);
				System.out
						.println("Saisissez la date de depart (Format date dd/mm/aaaa)");
				String dateDepart = sc.nextLine();
				sc = new Scanner(System.in);
				System.out
						.println("Saisissez la date de d'arrivee (Format date dd/mm/aaaa)");
				String dateArrivee = sc.nextLine();
				sc = new Scanner(System.in);
				System.out
						.println("Saisissez le type de véhicule parmis les véhicules suivants : CAMION, BATEAU, AVION");
				String typeVehicule = sc.nextLine();
				sc = new Scanner(System.in);

				// Recherche de l'agence de départ
				AgenceItf agenceDepart = null;

				if (stub.getNom().equals(villeDepart))
					agenceDepart = stub;
				else {
					for (AgenceItf a : AutresAgences) {
						if (a.getNom().equals(villeDepart))
							agenceDepart = a;
					}
				}
				// Recherche de l'agence d'arrivée
				AgenceItf agenceArrivee = null;

				if (stub.getNom().equals(villeArrivee))
					agenceArrivee = stub;
				else {
					for (AgenceItf a : AutresAgences) {
						if (a.getNom().equals(agenceArrivee))
							agenceArrivee = a;
					}
				}

				int dDepart = Integer.parseInt(dateDepart.split("/")[0]);
				int mDepart = Integer.parseInt(dateDepart.split("/")[1]) - 1;
				int yDepart = Integer.parseInt(dateDepart.split("/")[2]);

				int dArrivee = Integer.parseInt(dateArrivee.split("/")[0]);
				int mArrivee = Integer.parseInt(dateArrivee.split("/")[1]) - 1;
				int yArrivee = Integer.parseInt(dateArrivee.split("/")[2]);

				Vehicule v = agenceDepart.rechercherVehiculeLibre(new Date(yDepart,
						mDepart, dDepart), new Date(yArrivee, mArrivee,
						dArrivee), TypeVehicule.valueOf(typeVehicule),
						agenceDepart);
				
				if(v == null){
					System.out.println("Pas de véhicule de ce type disponible à cette date");
					break;
				}
				
				double prix = agenceDepart.calculerPrix(v, villeDepart, villeArrivee);

				System.out
						.println("Le prix de cette réservation est de " + prix + " euros");
				System.out
						.println("Voulez vous valider cette réservation 1/Oui 2/Non : ");
				int prixLocation = sc.nextInt();

				if (prixLocation == 1) {
					Reservation r = v.reserver(new Date(yDepart, mDepart,
							dDepart), new Date(yArrivee, mArrivee, dArrivee),
							agenceDepart, agenceArrivee);
					System.out.println("Voici l'ID de votre réservation : "
							+ r.getId());
				}
				break;
			}
		}
	}

	public AgenceImpl(String nom) {
		this.id = IDENT_AUTO++;
		listeVehicules = new ArrayList<Vehicule>();
		this.nom = nom;
		this.loadProperties();
	}

	public List<Vehicule> getListeVehicules() {
		return listeVehicules;
	}

	public String getNom() {
		return nom;
	}

	public void setNom(String nom) {
		this.nom = nom;
	}

	public Reservation passerReservation(Vehicule vehicule, Date dateDepart,
			Date dateArrivee, AgenceItf agenceDepart, AgenceItf agenceArrivee) {
		if (listeVehicules.contains(vehicule))
			return vehicule.reserver(dateDepart, dateArrivee, agenceDepart,
					agenceArrivee);
		return null;
	}

	public Vehicule rechercherVehiculeLibre(Date dateDepart, Date dateArrivee,
			TypeVehicule typeVehicule, AgenceItf agenceDepart) {
		// g�rer pour r�servation dans une autre agence
		boolean dispo = false;
		for (Vehicule v : listeVehicules) {
			if (typeVehicule.equals(v.getType())) {
				dispo = true;
				ArrayList<Reservation> listeResa = (ArrayList<Reservation>) v
						.getListeReservation();
				for (Reservation r : listeResa) {
					if ((dateDepart.after(r.getDateDebut()) && dateDepart
							.before(r.getDateRetour()))
							|| (dateArrivee.after(r.getDateDebut()) && dateArrivee
									.before(r.getDateRetour()))) {
						dispo = false;
					}
				}
			}
			if (dispo == true)
				return v;
		}
		return null;

	}

	public void ChargerAgences(List<AgenceItf> Agences, Registry myRegistry,
			Properties prop) {
		try {
			myRegistry = LocateRegistry.getRegistry(
					(String) prop.getProperty("agence2ip"),
					Integer.parseInt(prop.getProperty("port")));
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			AutresAgences.add((AgenceItf) myRegistry.lookup(prop.getProperty("agence2")));
		} catch (AccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			myRegistry = LocateRegistry.getRegistry(
					(String) prop.getProperty("agence3ip"),
					Integer.parseInt(prop.getProperty("port")));
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			AutresAgences.add((AgenceItf) myRegistry.lookup(prop.getProperty("agence3")));
		} catch (AccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public double calculerPrix(Vehicule vehicule, String agenceDepart,
			String agenceArrivee) {
		Properties prop = new Properties();
		prop.clear();
		double coefVehicule = 0.0;
		double distanceAgence = 0.0;
		
		coefVehicule = vehicule.getCoefficient();

		try {
			FileInputStream in = new FileInputStream("agence.properties");
			prop.load(in);

			distanceAgence = Double.parseDouble((String) prop.get("distance"
					+ agenceDepart + agenceArrivee));

			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return coefVehicule * distanceAgence;
	}

	public boolean annulerReservation(int id) {
		for (Vehicule v : listeVehicules) {
			for (Reservation r : v.listeReservation) {
				if (r.getId() == id) {
					return v.libererVehicule(r);
				}
			}
		}

		return false;
	}

	public int getId() {
		return id;
	}

	public void loadProperties() {
		Properties prop = new Properties();
		prop.clear();
		try {
			FileInputStream in = new FileInputStream("agence.properties");
			prop.load(in);
			int nbBat = Integer.parseInt(prop.getProperty("nombreBateaux"));
			int nbAvi = Integer.parseInt(prop.getProperty("nombreAvions"));
			int nbCam = Integer.parseInt(prop.getProperty("nombreCamions"));

			for (int i = 0; i < nbBat; i++) {
				listeVehicules.add(new Vehicule(TypeVehicule.BATEAU));
			}

			for (int i = 0; i < nbAvi; i++) {
				listeVehicules.add(new Vehicule(TypeVehicule.AVION));
			}

			for (int i = 0; i < nbCam; i++) {
				listeVehicules.add(new Vehicule(TypeVehicule.CAMION));
			}

			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}